home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / tar.gnu / sprite / rtape_lib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-29  |  12.1 KB  |  630 lines

  1. /* Remote tape emulator subroutines.
  2.    Copyright (C) 1988 Free Software Foundation
  3.  
  4. This file is part of GNU Tar.
  5.  
  6. GNU Tar is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU Tar is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Tar; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* JF: modified to make all rmtXXX calls into macros for speed */
  21.  
  22. #ifndef lint
  23. static char *RCSid = "$Header: /sprite/src/cmds/tar.gnu/sprite/RCS/rtape_lib.c,v 1.3 92/03/28 17:32:35 kupfer Exp $";
  24. #endif
  25.  
  26. /*
  27.  * $Log:    rtape_lib.c,v $
  28.  * Revision 1.3  92/03/28  17:32:35  kupfer
  29.  * Lint.
  30.  * 
  31.  * Revision 1.2  90/06/28  15:34:58  rab
  32.  * Added support for long filenames and long symbolic linkes.
  33.  * 
  34.  * Revision 1.1  90/03/21  21:54:41  rab
  35.  * Initial revision
  36.  * 
  37.  * Revision 1.7  89/03/23  14:09:51  root
  38.  * Fix from haynes@ucscc.ucsc.edu for use w/compat. ADR.
  39.  * 
  40.  * Revision 1.6  88/10/25  17:04:29  root
  41.  * rexec code and a bug fix from srs!dan, miscellanious cleanup. ADR.
  42.  * 
  43.  * Revision 1.5  88/10/25  16:30:17  root
  44.  * Fix from jeff@gatech.edu for getting user@host:dev right. ADR.
  45.  * 
  46.  * Revision 1.4  87/10/30  10:36:12  root
  47.  * Made 4.2 syntax a compile time option. ADR.
  48.  * 
  49.  * Revision 1.3  87/04/22  11:16:48  root
  50.  * Two fixes from parmelee@wayback.cs.cornell.edu to correctly
  51.  * do fd biasing and rmt protocol on 'S' command. ADR.
  52.  * 
  53.  * Revision 1.2  86/10/09  16:38:53  root
  54.  * Changed to reflect 4.3BSD rcp syntax. ADR.
  55.  * 
  56.  * Revision 1.1  86/10/09  16:17:35  root
  57.  * Initial revision
  58.  * 
  59.  */
  60.  
  61. /*
  62.  *    rmt --- remote tape emulator subroutines
  63.  *
  64.  *    Originally written by Jeff Lee, modified some by Arnold Robbins
  65.  *
  66.  *    WARNING:  The man page rmt(8) for /etc/rmt documents the remote mag
  67.  *    tape protocol which rdump and rrestore use.  Unfortunately, the man
  68.  *    page is *WRONG*.  The author of the routines I'm including originally
  69.  *    wrote his code just based on the man page, and it didn't work, so he
  70.  *    went to the rdump source to figure out why.  The only thing he had to
  71.  *    change was to check for the 'F' return code in addition to the 'E',
  72.  *    and to separate the various arguments with \n instead of a space.  I
  73.  *    personally don't think that this is much of a problem, but I wanted to
  74.  *    point it out.
  75.  *    -- Arnold Robbins
  76.  *
  77.  *    Redone as a library that can replace open, read, write, etc, by
  78.  *    Fred Fish, with some additional work by Arnold Robbins.
  79.  */
  80.  
  81. /*
  82.  *    MAXUNIT --- Maximum number of remote tape file units
  83.  *
  84.  *    READ --- Return the number of the read side file descriptor
  85.  *    WRITE --- Return the number of the write side file descriptor
  86.  */
  87.  
  88. /* #define RMTIOCTL    1 */
  89. /* #define USE_REXEC    1    /* rexec code courtesy of Dan Kegel, srs!dan */
  90.  
  91. #include <stdio.h>
  92. #include <signal.h>
  93. #include <sys/types.h>
  94.  
  95. #ifdef RMTIOCTL
  96. #include <sys/ioctl.h>
  97. #include <sys/mtio.h>
  98. #endif
  99.  
  100. #ifdef USE_REXEC
  101. #include <netdb.h>
  102. #endif
  103.  
  104. #include <errno.h>
  105. #include <setjmp.h>
  106. #include <sys/stat.h>
  107.  
  108. #define BUFMAGIC    64    /* a magic number for buffer sizes */
  109. #define MAXUNIT    4
  110.  
  111. #define READ(fd)    (Ctp[fd][0])
  112. #define WRITE(fd)    (Ptc[fd][1])
  113.  
  114. static int Ctp[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  115. static int Ptc[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  116.  
  117. extern int errno;
  118.  
  119. char *__rmt_path;
  120.  
  121. /*
  122.  *    _rmt_panic --- close off a remote tape connection
  123.  */
  124.  
  125. static void _rmt_panic(fildes)
  126. int fildes;
  127. {
  128.     close(READ(fildes));
  129.     close(WRITE(fildes));
  130.     READ(fildes) = -1;
  131.     WRITE(fildes) = -1;
  132. }
  133.  
  134.  
  135.  
  136. /*
  137.  *    command --- attempt to perform a remote tape command
  138.  */
  139.  
  140. static int command(fildes, buf)
  141. int fildes;
  142. char *buf;
  143. {
  144.     register int blen;
  145. #ifdef USG
  146.     void (*pstat)();
  147. #else
  148.     int (*pstat)();
  149. #endif
  150.  
  151. /*
  152.  *    save current pipe status and try to make the request
  153.  */
  154.  
  155.     blen = strlen(buf);
  156.     pstat = (int (*)()) signal(SIGPIPE, SIG_IGN);
  157.     if (write(WRITE(fildes), buf, blen) == blen)
  158.     {
  159.         signal(SIGPIPE, pstat);
  160.         return(0);
  161.     }
  162.  
  163. /*
  164.  *    something went wrong. close down and go home
  165.  */
  166.  
  167.     signal(SIGPIPE, pstat);
  168.     _rmt_panic(fildes);
  169.  
  170.     errno = EIO;
  171.     return(-1);
  172. }
  173.  
  174.  
  175.  
  176. /*
  177.  *    status --- retrieve the status from the pipe
  178.  */
  179.  
  180. static int status(fildes)
  181. int fildes;
  182. {
  183.     int i;
  184.     char c, *cp;
  185.     char buffer[BUFMAGIC];
  186.  
  187. /*
  188.  *    read the reply command line
  189.  */
  190.  
  191.     for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++)
  192.     {
  193.         if (read(READ(fildes), cp, 1) != 1)
  194.         {
  195.             _rmt_panic(fildes);
  196.             errno = EIO;
  197.             return(-1);
  198.         }
  199.         if (*cp == '\n')
  200.         {
  201.             *cp = 0;
  202.             break;
  203.         }
  204.     }
  205.  
  206.     if (i == BUFMAGIC)
  207.     {
  208.         _rmt_panic(fildes);
  209.         errno = EIO;
  210.         return(-1);
  211.     }
  212.  
  213. /*
  214.  *    check the return status
  215.  */
  216.  
  217.     for (cp = buffer; *cp; cp++)
  218.         if (*cp != ' ')
  219.             break;
  220.  
  221.     if (*cp == 'E' || *cp == 'F')
  222.     {
  223.         errno = atoi(cp + 1);
  224.         while (read(READ(fildes), &c, 1) == 1)
  225.             if (c == '\n')
  226.                 break;
  227.  
  228.         if (*cp == 'F')
  229.             _rmt_panic(fildes);
  230.  
  231.         return(-1);
  232.     }
  233.  
  234. /*
  235.  *    check for mis-synced pipes
  236.  */
  237.  
  238.     if (*cp != 'A')
  239.     {
  240.         _rmt_panic(fildes);
  241.         errno = EIO;
  242.         return(-1);
  243.     }
  244.  
  245.     return(atoi(cp + 1));
  246. }
  247.  
  248. #ifdef USE_REXEC
  249.  
  250. /*
  251.  * _rmt_rexec
  252.  *
  253.  * execute /etc/rmt on a remote system using rexec().
  254.  * Return file descriptor of bidirectional socket for stdin and stdout
  255.  * If username is NULL, or an empty string, uses current username.
  256.  *
  257.  * ADR: By default, this code is not used, since it requires that
  258.  * the user have a .netrc file in his/her home directory, or that the
  259.  * application designer be willing to have rexec prompt for login and
  260.  * password info. This may be unacceptable, and .rhosts files for use
  261.  * with rsh are much more common on BSD systems.
  262.  */
  263.  
  264. static int
  265. _rmt_rexec(host, user)
  266. char *host;
  267. char *user;        /* may be NULL */
  268. {
  269.     struct servent *rexecserv;
  270.  
  271.     rexecserv = getservbyname("exec", "tcp");
  272.     if (NULL == rexecserv) {
  273.         fprintf (stderr, "? exec/tcp: service not available.");
  274.         exit (-1);
  275.     }
  276.     if ((user != NULL) && *user == '\0')
  277.         user = (char *) NULL;
  278.     return rexec (&host, rexecserv->s_port, user, NULL,
  279.             "/etc/rmt", (int *)NULL);
  280. }
  281. #endif /* USE_REXEC */
  282.  
  283. /*
  284.  *    _rmt_open --- open a magtape device on system specified, as given user
  285.  *
  286.  *    file name has the form [user@]system:/dev/????
  287. #ifdef COMPAT
  288.  *    file name has the form system[.user]:/dev/????
  289. #endif
  290.  */
  291.  
  292. #define MAXHOSTLEN    257    /* BSD allows very long host names... */
  293.  
  294. int __rmt_open (path, oflag, mode, bias)
  295. char *path;
  296. int oflag;
  297. int mode;
  298. int bias;
  299. {
  300.     int i, rc;
  301.     char buffer[BUFMAGIC];
  302.     char system[MAXHOSTLEN];
  303.     char device[BUFMAGIC];
  304.     char login[BUFMAGIC];
  305.     char *sys, *dev, *user;
  306.  
  307.     sys = system;
  308.     dev = device;
  309.     user = login;
  310.  
  311. /*
  312.  *    first, find an open pair of file descriptors
  313.  */
  314.  
  315.     for (i = 0; i < MAXUNIT; i++)
  316.         if (READ(i) == -1 && WRITE(i) == -1)
  317.             break;
  318.  
  319.     if (i == MAXUNIT)
  320.     {
  321.         errno = EMFILE;
  322.         return(-1);
  323.     }
  324.  
  325. /*
  326.  *    pull apart system and device, and optional user
  327.  *    don't munge original string
  328.  *    if COMPAT is defined, also handle old (4.2) style person.site notation.
  329.  */
  330.  
  331.     while (*path != '@'
  332. #ifdef COMPAT
  333.             && *path != '.'
  334. #endif
  335.             && *path != ':') {
  336.         *sys++ = *path++;
  337.     }
  338.     *sys = '\0';
  339.     path++;
  340.  
  341.     if (*(path - 1) == '@')
  342.     {
  343.         (void) strcpy (user, system);    /* saw user part of user@host */
  344.         sys = system;            /* start over */
  345.         while (*path != ':') {
  346.             *sys++ = *path++;
  347.         }
  348.         *sys = '\0';
  349.         path++;
  350.     }
  351. #ifdef COMPAT
  352.     else if (*(path - 1) == '.')
  353.     {
  354.         while (*path != ':') {
  355.             *user++ = *path++;
  356.         }
  357.         *user = '\0';
  358.         path++;
  359.     }
  360. #endif
  361.     else
  362.         *user = '\0';
  363.  
  364.     while (*path) {
  365.         *dev++ = *path++;
  366.     }
  367.     *dev = '\0';
  368.  
  369. #ifdef USE_REXEC
  370. /* 
  371.  *    Execute the remote command using rexec 
  372.  */
  373.     READ(i) = WRITE(i) = _rmt_rexec(system, login);
  374.     if (READ(i) < 0)
  375.         return -1;
  376. #else
  377. /*
  378.  *    setup the pipes for the 'rsh' command and fork
  379.  */
  380.  
  381.     if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
  382.         return(-1);
  383.  
  384.     if ((rc = fork()) == -1)
  385.         return(-1);
  386.  
  387.     if (rc == 0)
  388.     {
  389.         close(0);
  390.         dup(Ptc[i][0]);
  391.         close(Ptc[i][0]); close(Ptc[i][1]);
  392.         close(1);
  393.         dup(Ctp[i][1]);
  394.         close(Ctp[i][0]); close(Ctp[i][1]);
  395.         (void) setuid (getuid ());
  396.         (void) setgid (getgid ());
  397.         if (*login)
  398.         {
  399.             execl("/usr/ucb/rsh", "rsh", system, "-l", login,
  400.                 "/etc/rmt", (char *) 0);
  401.             execl("/usr/bin/remsh", "remsh", system, "-l", login,
  402.                 "/etc/rmt", (char *) 0);
  403.             execl("/usr/bin/rsh", "rsh", system, "-l", login,
  404.                 "/etc/rmt", (char *) 0);
  405.             execl("/usr/bsd/rsh", "rsh", system, "-l", login,
  406.                 "/etc/rmt", (char *)0);
  407.         }
  408.         else
  409.         {
  410.             execl("/usr/ucb/rsh", "rsh", system,
  411.                 "/etc/rmt", (char *) 0);
  412.             execl("/usr/bin/remsh", "remsh", system,
  413.                 "/etc/rmt", (char *) 0);
  414.             execl("/usr/bin/rsh", "rsh", system,
  415.                 "/etc/rmt", (char *) 0);
  416.             execl("/usr/bsd/rsh", "rsh", system,
  417.                 "/etc/rmt", (char *) 0);
  418.         }
  419.  
  420. /*
  421.  *    bad problems if we get here
  422.  */
  423.  
  424.         perror("remote shell exec");
  425.         exit(1);
  426.     }
  427.  
  428.     close(Ptc[i][0]); close(Ctp[i][1]);
  429. #endif
  430.  
  431. /*
  432.  *    now attempt to open the tape device
  433.  */
  434.  
  435.     sprintf(buffer, "O%s\n%d\n", device, oflag);
  436.     if (command(i, buffer) == -1 || status(i) == -1)
  437.         return(-1);
  438.  
  439.     return(i+bias);
  440. }
  441.  
  442.  
  443.  
  444. /*
  445.  *    _rmt_close --- close a remote magtape unit and shut down
  446.  */
  447.  
  448.  int __rmt_close(fildes)
  449. int fildes;
  450. {
  451.     int rc;
  452.  
  453.     if (command(fildes, "C\n") != -1)
  454.     {
  455.         rc = status(fildes);
  456.  
  457.         _rmt_panic(fildes);
  458.         return(rc);
  459.     }
  460.  
  461.     return(-1);
  462. }
  463.  
  464.  
  465.  
  466. /*
  467.  *    _rmt_read --- read a buffer from a remote tape
  468.  */
  469.  
  470. int __rmt_read(fildes, buf, nbyte)
  471. int fildes;
  472. char *buf;
  473. int nbyte;
  474. {
  475.     int rc, i;
  476.     char buffer[BUFMAGIC];
  477.  
  478.     sprintf(buffer, "R%d\n", nbyte);
  479.     if (command(fildes, buffer) == -1 || (rc = status(fildes)) == -1)
  480.         return(-1);
  481.  
  482.     for (i = 0; i < rc; i += nbyte, buf += nbyte)
  483.     {
  484.         nbyte = read(READ(fildes), buf, rc);
  485.         if (nbyte <= 0)
  486.         {
  487.             _rmt_panic(fildes);
  488.             errno = EIO;
  489.             return(-1);
  490.         }
  491.     }
  492.  
  493.     return(rc);
  494. }
  495.  
  496.  
  497.  
  498. /*
  499.  *    _rmt_write --- write a buffer to the remote tape
  500.  */
  501.  
  502. int __rmt_write(fildes, buf, nbyte)
  503. int fildes;
  504. char *buf;
  505. unsigned int nbyte;
  506. {
  507.     char buffer[BUFMAGIC];
  508. #ifdef USG
  509.     void (*pstat)();
  510. #else
  511.     int (*pstat)();
  512. #endif
  513.  
  514.     sprintf(buffer, "W%d\n", nbyte);
  515.     if (command(fildes, buffer) == -1)
  516.         return(-1);
  517.  
  518.     pstat = (int (*)()) signal(SIGPIPE, SIG_IGN);
  519.     if (write(WRITE(fildes), buf, nbyte) == nbyte)
  520.     {
  521.         signal (SIGPIPE, pstat);
  522.         return(status(fildes));
  523.     }
  524.  
  525.     signal (SIGPIPE, pstat);
  526.     _rmt_panic(fildes);
  527.     errno = EIO;
  528.     return(-1);
  529. }
  530.  
  531.  
  532.  
  533. /*
  534.  *    _rmt_lseek --- perform an imitation lseek operation remotely
  535.  */
  536.  
  537. long __rmt_lseek(fildes, offset, whence)
  538. int fildes;
  539. long offset;
  540. int whence;
  541. {
  542.     char buffer[BUFMAGIC];
  543.  
  544.     sprintf(buffer, "L%d\n%d\n", offset, whence);
  545.     if (command(fildes, buffer) == -1)
  546.         return(-1);
  547.  
  548.     return(status(fildes));
  549. }
  550.  
  551.  
  552. /*
  553.  *    _rmt_ioctl --- perform raw tape operations remotely
  554.  */
  555.  
  556. #ifdef RMTIOCTL
  557. __rmt_ioctl(fildes, op, arg)
  558. int fildes, op;
  559. char *arg;
  560. {
  561.     char c;
  562.     int rc, cnt;
  563.     char buffer[BUFMAGIC];
  564.  
  565. /*
  566.  *    MTIOCOP is the easy one. nothing is transfered in binary
  567.  */
  568.  
  569.     if (op == MTIOCTOP)
  570.     {
  571.         sprintf(buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
  572.             ((struct mtop *) arg)->mt_count);
  573.         if (command(fildes, buffer) == -1)
  574.             return(-1);
  575.         return(status(fildes));
  576.     }
  577.  
  578. /*
  579.  *    we can only handle 2 ops, if not the other one, punt
  580.  */
  581.  
  582.     if (op != MTIOCGET)
  583.     {
  584.         errno = EINVAL;
  585.         return(-1);
  586.     }
  587.  
  588. /*
  589.  *    grab the status and read it directly into the structure
  590.  *    this assumes that the status buffer is (hopefully) not
  591.  *    padded and that 2 shorts fit in a long without any word
  592.  *    alignment problems, ie - the whole struct is contiguous
  593.  *    NOTE - this is probably NOT a good assumption.
  594.  */
  595.  
  596.     if (command(fildes, "S") == -1 || (rc = status(fildes)) == -1)
  597.         return(-1);
  598.  
  599.     for (; rc > 0; rc -= cnt, arg += cnt)
  600.     {
  601.         cnt = read(READ(fildes), arg, rc);
  602.         if (cnt <= 0)
  603.         {
  604.             _rmt_panic(fildes);
  605.             errno = EIO;
  606.             return(-1);
  607.         }
  608.     }
  609.  
  610. /*
  611.  *    now we check for byte position. mt_type is a small integer field
  612.  *    (normally) so we will check its magnitude. if it is larger than
  613.  *    256, we will assume that the bytes are swapped and go through
  614.  *    and reverse all the bytes
  615.  */
  616.  
  617.     if (((struct mtget *) arg)->mt_type < 256)
  618.         return(0);
  619.  
  620.     for (cnt = 0; cnt < rc; cnt += 2)
  621.     {
  622.         c = arg[cnt];
  623.         arg[cnt] = arg[cnt+1];
  624.         arg[cnt+1] = c;
  625.     }
  626.  
  627.     return(0);
  628.   }
  629. #endif /* RMTIOCTL */
  630.